%%%-------------------------------------------------------------------
%%% @author wu_huidong@126.com
%%% @copyright (C) 2020, <WuHuiDong>
%%% @doc
%%% Unity NavMesh Erlang NIF
%%% @end
%%% Created : 27. 10月 2020 14:16
%%%-------------------------------------------------------------------
-module(x_nav).
-author("wu_huidong@126.com").

-include("x_nav.hrl").

-export([
    load_map/2,
    has_map/1,
    get_border/1,
    maps/0,
    find_path/3,
    find_path/4,
    is_walkable/2,
    is_walkable/3,
    reasonal_pos/3,
    reasonal_pos/4,
    raycast/3,
    raycast/4
]).

-type map_id() :: non_neg_integer().                    %% 地图Id
-type exclude() :: non_neg_integer().                   %% 地图掩码
-type radius() :: number().                             %% 半径
-type pos() :: {float(), float(), float()}.             %% 位置坐标{x轴,y轴,z轴}

-export_type([
    map_id/0,
    exclude/0,
    radius/0,
    pos/0
]).

-on_load(init/0).

init() ->
    Path = filename:join(code:priv_dir(?x_nav), atom_to_list(?MODULE)),
    erlang:load_nif(Path, 0).

%% @doc 载入地图
-spec load_map(MapId, NavMeshPath) -> ok when
    MapId :: map_id(),
    NavMeshPath :: string().
load_map(_MapId, _NavMeshPath) ->
    erlang:nif_error(undef).

%% @doc 是否有地图
-spec has_map(MapId) -> Result when
    MapId :: map_id(),
    Result :: boolean().
has_map(_MapId) ->
    erlang:nif_error(undef).

%% @doc 载入的地图Id列表
-spec maps() -> Maps when
    Maps :: [map_id()].
maps() ->
    erlang:nif_error(undef).

%% @doc 获取地图边界
-spec get_border(MapId) -> Border when
    MapId :: map_id(),
    Border :: {pos(), pos()}.
get_border(_MapId) ->
    erlang:nif_error(undef).

%% @doc 两点间的路径, 参考{@link find_path/4}, Exclude为0
-spec find_path(MapId, StartPos, EndPos) -> Path when
    MapId :: map_id(),
    StartPos :: pos(),
    EndPos :: pos(),
    Path :: [pos()].
find_path(_MapId, _StartPos, _EndPos) ->
    find_path(_MapId, _StartPos, _EndPos, 0).

%% @doc 两点间的路径
-spec find_path(MapId, StartPos, EndPos, Exclude) -> Path when
    MapId :: map_id(),
    StartPos :: pos(),
    EndPos :: pos(),
    Exclude :: exclude(),
    Path :: [pos()].
find_path(_MapId, _StartPos, _EndPos, _Exclude) ->
    erlang:nif_error(undef).

%% @doc 是否可走, 参考{@link is_walkable/3}, Exclude为0
-spec is_walkable(MapId, Pos) -> Result when
    MapId :: map_id(),
    Pos :: pos(),
    Result :: boolean().
is_walkable(_MapId, _Pos) ->
    is_walkable(_MapId, _Pos, 0).

%% @doc 是否可走点
-spec is_walkable(MapId, Pos, Exclude) -> Result when
    MapId :: map_id(),
    Pos :: pos(),
    Exclude :: exclude(),
    Result :: boolean().
is_walkable(_MapId, _Pos, _Exclude) ->
    erlang:nif_error(undef).

%% @doc 在指定点半径内寻找可走点, 参考{@link reasonal_pos/4}, Exclude为0
-spec reasonal_pos(MapId, Pos, Radius) -> NewPos when
    MapId :: map_id(),
    Pos :: pos(),
    Radius :: radius(),
    NewPos :: pos() | undefined.
reasonal_pos(MapId, Pos, Radius) ->
    reasonal_pos(MapId, Pos, Radius, 0).

%% @doc 在指定点半径内寻找可走点
-spec reasonal_pos(MapId, Pos, Radius, Exclude) -> NewPos when
    MapId :: map_id(),
    Pos :: x_aoi:pos(),
    Radius :: radius(),
    Exclude :: exclude(),
    NewPos :: pos() | undefined.
reasonal_pos(_MapId, _Pos, _Radius, _Exclude) ->
    erlang:nif_error(undef).

%% @doc 射线碰撞点, 参考{@link raycast/4}, Exclude为0
-spec raycast(MapId, StartPos, EndPos) -> Pos when
    MapId :: map_id(),
    StartPos :: pos(),
    EndPos :: pos(),
    Pos :: pos().
raycast(MapId, StartPos, EndPos) ->
    raycast(MapId, StartPos, EndPos, 0).

%% @doc 射线碰撞点
-spec raycast(MapId, StartPos, EndPos, Exclude) -> Pos when
    MapId :: map_id(),
    StartPos :: pos(),
    EndPos :: pos(),
    Exclude :: exclude(),
    Pos :: pos().
raycast(_MapId, _StartPos, _EndPos, _Exclude) ->
    erlang:nif_error(undef).